package tr.edu.ege.kipler.satisfiability.clash;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import tr.edu.ege.kipler.satisfiability.container.ABox;
import tr.edu.ege.kipler.satisfiability.container.ConceptCategory;
import tr.edu.ege.kipler.satisfiability.container.Individual;
import tr.edu.ege.kipler.satisfiability.container.WorldConstraintSystem;
import tr.edu.ege.kipler.satisfiability.container.operational.FilterType;
import tr.edu.ege.kipler.satisfiability.container.operational.RelatedIndividualWithTypeFilterFactory;
import tr.edu.ege.kipler.syntax.atomicformula.ConceptAssertion;
import tr.edu.ege.kipler.syntax.atomicformula.Formula;
import tr.edu.ege.kipler.syntax.atomicformula.ObjectRoleAssertion;
import tr.edu.ege.kipler.syntax.atomicformula.SameIndividualAssertion;
import tr.edu.ege.kipler.syntax.concept.Concept;
import tr.edu.ege.kipler.syntax.concept.QualifiedNoRestriction;

/**
 * 
 * @author İnanç Seylan
 *
 */
public class DedicatedQNRClashDetectionStrategy implements
		ClashDetectionStrategy {

	private Set<WorldConstraintSystem> dependencySet = new HashSet<WorldConstraintSystem>();

	private ABox abox;

	public Set<WorldConstraintSystem> getDependencySet() {
		return dependencySet;
	}

	public String getExplanation() {
		return "QR";
	}

	public boolean hasClash(ABox abox, Formula formula) {
		boolean result = false;
		this.abox = abox;
		if (formula instanceof ConceptAssertion) {
			ConceptAssertion ca = (ConceptAssertion) formula;
			result = checkConceptAssertion(ca);
		} else if (formula instanceof ObjectRoleAssertion) {
			ObjectRoleAssertion objRole = (ObjectRoleAssertion) formula;
			result = checkObjectRoleAssertion(objRole);
		} else if (formula instanceof SameIndividualAssertion) {
			SameIndividualAssertion ia = (SameIndividualAssertion) formula;
			result = checkInequalityAssertion(ia);
		}
		return result;
	}

	/**
	 * @param abox
	 * @param result
	 * @param ia
	 * @return
	 */
	private boolean checkInequalityAssertion(SameIndividualAssertion ia) {
		boolean result = false;
		if (ia.isNegated()) {
			// if this operation causes a clash, the neighbor of lhs is also
			// a neighbor of rhs
			Individual lhs = abox.getIndividual(ia.getLhs());
			result = ownersViolateRestriction(abox.neighborIterator(lhs));
		}
		return result;
	}

	/**
	 * @param abox
	 * @param objRole
	 * @return
	 */
	private boolean checkObjectRoleAssertion(ObjectRoleAssertion objRole) {
		boolean result = false;
		Individual owner = abox.getIndividual(objRole.getOwner());
		Individual filler = abox.getIndividual(objRole.getFiller());
		result = ownerViolatesRestriction(owner)
				|| ownerViolatesRestriction(filler);
		return result;
	}

	/**
	 * @param abox
	 * @param result
	 * @param ca
	 * @return
	 */
	private boolean checkConceptAssertion(ConceptAssertion ca) {
		Individual indv = abox.getIndividual(ca.getName());
		boolean violateAsOwner = false;
		if (ca.getConcept() instanceof QualifiedNoRestriction) {
			violateAsOwner = ownerViolatesRestriction(indv);
		}
		return violateAsOwner
				|| ownersViolateRestriction(abox.neighborIterator(indv));
	}

	private boolean ownersViolateRestriction(Iterator<Individual> ownerIter) {
		boolean result = false;
		while (ownerIter.hasNext()) {
			result = ownerViolatesRestriction(ownerIter.next());
			if (result == true) {
				break;
			}
		}
		return result;
	}

	/**
	 * @param abox
	 * @param result
	 * @param owner
	 * @return
	 */
	private boolean ownerViolatesRestriction(Individual owner) {
		boolean result = false;
		for (Iterator<Concept> i = owner
				.conceptIterator(ConceptCategory.AT_MOST); i.hasNext();) {
			Concept concept = i.next();
			QualifiedNoRestriction qr = (QualifiedNoRestriction) concept;
			if (atMostViolated(qr, owner)) {
				result = true;
				break;
			}
		}
		return result;
	}

	private boolean atMostViolated(QualifiedNoRestriction qr, Individual indv) {
		boolean result = false;
		Set<Individual> neighbors = RelatedIndividualWithTypeFilterFactory
				.getFilter(FilterType.TYPED_NEIGHBOR, abox, indv,
						qr.getRole(), qr.getConcept()).filter();
		InstantQNRClashDetectionStrategy instantClashDetection = new InstantQNRClashDetectionStrategy(
				neighbors);
		instantClashDetection.setABox(abox);
		if (instantClashDetection.atMostViolated(qr, indv)) {
			result = true;
			dependencySet = instantClashDetection.getDependencySet();
		}
		return result;
	}
}
